package site.shihuan.helpdesk.im;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import site.shihuan.helpdesk.common.manager.TokenManager;
import site.shihuan.helpdesk.common.model.Constants;
import site.shihuan.helpdesk.common.model.JwtUser;
import site.shihuan.helpdesk.im.dao.SvcClerkDao;
import site.shihuan.helpdesk.im.exception.CommandException;
import site.shihuan.helpdesk.im.core.CommandHandler;
import site.shihuan.helpdesk.im.core.MessageDecoder;
import site.shihuan.helpdesk.im.exception.DecodeException;
import site.shihuan.helpdesk.im.message.BaseMessage;

import javax.annotation.PreDestroy;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

/**
 * IM WebSocket
 *
 * @author 周世焕
 * @Date 2021/2/2 19:01
 */
@Slf4j
@ServerEndpoint("/v1/im/{tenantId}/{type}/{value}")
@Component
public class WebSocket {

    public static TokenManager tokenManager;

    public static CommandHandler commandHandler;

    public static SessionContextHolder sessionContextHolder;

    public static SvcClerkDao clerkDao;

    @Autowired
    public void setTokenManager(TokenManager tokenManager) {
        WebSocket.tokenManager = tokenManager;
    }

    @Autowired
    public void setCommandHandler(CommandHandler commandHandler) {
        WebSocket.commandHandler = commandHandler;
    }

    @Autowired
    public void setUserContextHolder(SessionContextHolder sessionContextHolder) {
        WebSocket.sessionContextHolder = sessionContextHolder;
    }

    @Autowired
    public void setClerkDao(SvcClerkDao svcClerkDao) {
        WebSocket.clerkDao = svcClerkDao;
    }

    /**
     * 监听连接建立
     * @param session
     * @param value type为VISITOR，则value为clientId;type为DEFAULT，则value为token
     * @param type VISITOR和DEFAULT
     * @throws IOException
     */
    @OnOpen
    public void opOpen(Session session, @PathParam("tenantId") String tenantId,@PathParam("type") String type,
                       @PathParam("value") String value) throws IOException {
        log.debug("onOpen:{},{},{}",tenantId,type,value);
        if(Constants.ROLE_DEFAULT.equals(type)) {
            JwtUser jwtUser = tokenManager.getUserInfo(value);
            /**
             * 检查该用户是否为clerk客服职员
             */
            if(jwtUser == null || !tenantId.equals(jwtUser.getTenantId())) {
                session.close();
                return;
            }
            sessionContextHolder.addUser(jwtUser,session);
        }else if(Constants.ROLE_VISITOR.equals(type)){
            JwtUser jwtUser = new JwtUser();
            jwtUser.setUid(value);
            jwtUser.setTenantId(tenantId);
            jwtUser.setRole(Constants.ROLE_VISITOR);
            sessionContextHolder.addVisitor(jwtUser,session);
        }else{
            session.close();
        }
    }

    /**
     * 监听关闭连接
     */
    @OnClose
    public void onClose(Session session) {
        log.debug("onClose");
        sessionContextHolder.remove(session);
    }

    /**
     * 发生错误
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        log.debug("因未能捕获的错误导致断开：{}",error);
    }

    /**
     * 监听消息接收
     * @param data
     */
    @OnMessage
    public void onMessage(String data,Session session) {
        try {
            BaseMessage message = MessageDecoder.decode(data);
            commandHandler.handleCommand(session,message);
        }catch (DecodeException e){
            log.debug("解码错误",e);
        } catch (CommandException e) {
            log.debug("命令处理错误",e);
        } catch (IOException e) {
            log.debug("消息传输错误",e);
        }
    }
}
